package com.wizo.csb.records;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Properties;
import java.util.Vector;

import com.wizo.csb.records.exporter.RecordsExporter;

class SeriesUnit{
	public long _time;
	public long _operations;
	public double _averageLatency;
	
	public SeriesUnit(long time, long operations, double averageLatency){
		_time = time;
		_operations = operations;
		_averageLatency = averageLatency;
	}
	
	public void printUnit(){
		System.out.println("Time: "+_time);
		System.out.println("operations: "+_operations);
		System.out.println("averageLatency: "+_averageLatency);
		System.out.println("--------------------------------");
	}
}

public class OneRecordTimeSeries extends OneRecord{
	Vector<SeriesUnit> _measurements;
	long _operationsOfUnit;
	long _totalLatencyOfUnit;
	long _operations;
	long _totalLatency;
	long _min;
	long _max;
	
	public OneRecordTimeSeries(String name, Properties props){
		super(name);
		_operationsOfUnit = 0;
		_totalLatencyOfUnit = 0;
		_operations = 0;
		_totalLatency = 0;
		_min = -1;
		_max = -1;
		_measurements = new Vector<SeriesUnit>();
	}
	
	public synchronized void record(long latency){
		_operationsOfUnit++;
		_operations++;
		_totalLatencyOfUnit += latency;
		_totalLatency += latency;
		
		if((_min<0)||(latency<_min))
			_min = latency;
		if((_max<0)||(latency>_max))
			_max = latency;
		
		_latencies.add(latency);
	}
	
	public synchronized SeriesUnit checkEndOfUnit(long time){
		SeriesUnit unit = new SeriesUnit(time, _operationsOfUnit, 
				getAverageLatency(_totalLatencyOfUnit, _operationsOfUnit));
		_measurements.add(unit);
		_operationsOfUnit = 0;
		_totalLatencyOfUnit = 0;
		return unit;
	}
	
	public void reportOneRecord(RecordsExporter exporter) throws IOException{
		exporter.write("**********Operation "+getName()+" ***********");
	
		//write the phases into the exporter
		String timeLine = "| Time                     |";
		String time = "";
		String operationsLine= "| Operations               |";
		String operation = "";
		String averageLatencyLine= "| AverageLatency(ms)       |";
		String averageLatency = "";
		DecimalFormat format = new DecimalFormat("#,###.##");
		int index = 0;
		
		for(SeriesUnit unit:_measurements){
			time += makeFormatString(format.format(((double)unit._time)/1000), 10)+"|";
			operation += makeFormatString(format.format(unit._operations), 10)+"|";
			averageLatency += makeFormatString(format.format(unit._averageLatency), 10)+"|";

			if((++index)%10==0){
				exporter.write(timeLine+time);
				time = "";
				exporter.write(operationsLine+operation);
				operation = "";
				exporter.write(averageLatencyLine+averageLatency);
				averageLatency = "";
				exporter.write("");
			}
		}
		
		if(!time.equals("")){
			exporter.write(timeLine+time);
			exporter.write(operationsLine+operation);
			exporter.write(averageLatencyLine+averageLatency);
			exporter.write("");
		}
		
		//write the summary into the exporter
		exporter.write("*********************************************");
		exporter.write("Total Operation Count", format.format(_operations));
		exporter.write("Min Latency(ms)", format.format(_min));
		exporter.write("Max Latency(ms)", format.format(_max));
		exporter.write("Average Latency(ms)", format.format(
				getAverageLatency(_totalLatency, _operations)));
		exporter.write("*********************************************");
	}
	
	public void reportLatencies(RecordsExporter exporter) throws IOException{
		DecimalFormat format = new DecimalFormat("#,###.##");
		exporter.write(getName());
		for(long latency:_latencies){
			exporter.write(format.format(latency));
		}
	}
	
	private String makeFormatString(String origin, int length){
		if(origin.length()<length){
			do{
				origin += " ";
			}while(origin.length()<length);
		}else if(origin.length()>length){
			origin = origin.substring(0, length);
		}
		
		return origin;
	}
	
	private double getAverageLatency(long totalLatency, long operations){
		if(operations==0)
			return 0;
		return ((double)totalLatency)/((double)operations);
	}
	
}
